use chrono::{DateTime, Duration, Local};
use log::info;
use rand::Rng;
use std::collections::HashMap;

#[derive(Debug)]
pub struct ExecutionRecord {
    pub execution_time: DateTime<Local>,
}

#[derive(Debug)]
pub struct DailyTarget {
    pub date: chrono::NaiveDate,
    pub target_count: u32,
}

#[derive(Debug)]
pub struct ExecutionTracker {
    pub task_executions: HashMap<String, Vec<ExecutionRecord>>,
    pub last_execution_time: Option<DateTime<Local>>,
    pub daily_targets: HashMap<String, DailyTarget>,
}

impl ExecutionTracker {
    pub fn new() -> Self {
        Self {
            task_executions: HashMap::new(),
            last_execution_time: None,
            daily_targets: HashMap::new(),
        }
    }

    pub fn can_execute_task(
        &mut self,
        task_name: &str,
        min_interval_hours: u32,
        min_executions_per_day: u32,
        max_executions_per_day: u32,
    ) -> bool {
        let now = Local::now();
        let today = now.date_naive();
        let today_executions = self.get_today_executions_count(task_name, today);
        
        // 获取或生成今天的执行次数目标
        let today_target = self.get_or_generate_daily_target(
            task_name, 
            today, 
            min_executions_per_day, 
            max_executions_per_day
        );

        // 检查是否达到今日目标
        if today_executions >= today_target {
            info!(
                "任务 {} 今天已执行 {} 次，达到今日目标 {}",
                task_name, today_executions, today_target
            );
            return false;
        }

        // 检查时间间隔
        if let Some(last_execution) = self.get_last_execution_time(task_name) {
            let min_interval = Duration::hours(min_interval_hours as i64);
            if now - last_execution < min_interval {
                info!(
                    "任务 {} 距离上次执行时间太短，需要等待 {} 小时",
                    task_name, min_interval_hours
                );
                return false;
            }
        }

        info!(
            "任务 {} 今天已执行 {} 次，目标 {} 次，可以执行",
            task_name, today_executions, today_target
        );
        true
    }

    pub fn record_execution(&mut self, task_name: &str) {
        let execution = ExecutionRecord {
            execution_time: Local::now(),
        };

        let task_executions = self
            .task_executions
            .entry(task_name.to_string())
            .or_default();
        task_executions.push(execution);
        self.last_execution_time = Some(Local::now());

        // 清理过期的记录（保留最近7天的记录）
        self.cleanup_old_records();
    }

    pub fn get_last_execution_time(&self, task_name: &str) -> Option<DateTime<Local>> {
        self.task_executions
            .get(task_name)
            .and_then(|executions| executions.last())
            .map(|record| record.execution_time)
    }

    pub fn next_allowed_time(
        &self,
        task_name: &str,
        min_interval_hours: u32,
    ) -> Option<DateTime<Local>> {
        self.get_last_execution_time(task_name)
            .map(|last| last + Duration::hours(min_interval_hours as i64))
    }

    pub fn has_reached_daily_limit(&self, task_name: &str, max_executions_per_day: u32) -> bool {
        if max_executions_per_day == 0 {
            return false;
        }

        let today = Local::now().date_naive();
        let today_executions = self.get_today_executions_count(task_name, today);
        today_executions >= max_executions_per_day
    }

    fn get_today_executions_count(&self, task_name: &str, today: chrono::NaiveDate) -> u32 {
        self.task_executions
            .get(task_name)
            .map(|executions| {
                executions
                    .iter()
                    .filter(|record| record.execution_time.date_naive() == today)
                    .count() as u32
            })
            .unwrap_or(0)
    }
    
    pub fn get_today_executions_count_public(&self, task_name: &str) -> u32 {
        let today = Local::now().date_naive();
        self.get_today_executions_count(task_name, today)
    }
    
    fn get_or_generate_daily_target(
        &mut self,
        task_name: &str,
        today: chrono::NaiveDate,
        min_executions: u32,
        max_executions: u32,
    ) -> u32 {
        // 检查是否已有今天的目标
        if let Some(target) = self.daily_targets.get(task_name)
            && target.date == today
        {
            return target.target_count;
        }
        
        // 生成新的随机目标
        let target_count = if max_executions > min_executions {
            let mut rng = rand::rng();
            rng.random_range(min_executions..=max_executions)
        } else {
            max_executions
        };
        
        info!("任务 {} 今日执行目标: {} 次 (范围: {}-{})", 
            task_name, target_count, min_executions, max_executions);
        
        self.daily_targets.insert(
            task_name.to_string(),
            DailyTarget {
                date: today,
                target_count,
            },
        );
        
        target_count
    }
    
    pub fn get_today_target(&mut self, task_name: &str, min_exec: u32, max_exec: u32) -> u32 {
        let today = Local::now().date_naive();
        self.get_or_generate_daily_target(task_name, today, min_exec, max_exec)
    }

    fn cleanup_old_records(&mut self) {
        let cutoff = Local::now() - Duration::days(7);

        for executions in self.task_executions.values_mut() {
            executions.retain(|record| record.execution_time >= cutoff);
        }
    }
}
